home *** CD-ROM | disk | FTP | other *** search
- /* LogLibrary.c */
- /*
- * LogLibrary.c
- * Copyright © 1992-95 Apple Computer Inc. All Rights Reserved.
- * Programmed by Martin Minow,
- * Internet: minow@apple.com
- * AppleLink: MINOW
- *
- * Edit History
- * This library implements a drop-in logging capability for device drivers,
- * callback functions, applications, and all other Power Macintosh code segments
- * running under a version of system software that supports the System Name Registry
- * and Driver Services libraries defined in Designing PCI Cards and Drivers for
- * Power Macintosh Computers.
- *
- * The overall philosophy is that an application or driver allocates a record in
- * system resident memory that contains a small preamble and one or more short blocks
- * of data. The driver logs data to the log area, where each log record contains an
- * identification value, a timestamp and up to eight longwords of data. The data
- * entry is self-formatting, so a generic log display application may be written.
- *
- * To permit logging from primary interupt level (which precludes using Software
- * Interrupts), the log record common area is protected by a critical section
- * (test and set) variable. The log is "lossy" in that failure to enter the
- * critical section will lose data, but will not stall or block the caller.
- *
- * This function will crash (or fail to load) if the DriverServices library
- * is unavailable.
- *
- * LogLibrary.c may be linked into a PCI Device Driver: it does not call
- * any Macintosh Toolbox functions. The global symbol _LogLibraryGlobal
- * (Note the leading underscore) must be exported globally-shared.
- *
- * LogLibrary is intended for use by PowerPC native applications and other
- * program entities. A 68000 version, in LogLibrary68.c, can be used by
- * emulated applications and other code segments, such as MacsBug dcmd's.
- *
- * Usage:
- * PowerPC (native):
- * Include "LogLibrary.h" and LogLibrary.c in all compilations.
- * 68000 emulation
- * Include "LogLibrary.h" in all compilations. The first GetLogRecordPtr
- * call must be able to call the Code Fragment Manager -- which means that
- * it must be able to open files and allocate memory. You can call it
- * with a dummy argument "foo = GetLogRecordPtr("\pFoo");"
- *
- * Edit History
- * 1995.03.28 MM CompareAndSwap screw-up.
- * 1995.03.31 MM Removed UpTime return from CopyLogEntry (only the dcmd needs it)
- * Added LogLibraryUpTime to return UpTime in nanoseconds for 68000
- * functions.
- * ResolveLogLibraryLinkage is now a static function: it was global.
- * 1995.04.07 MM Some compilers mis-handle functions returning structures. Store
- * UpTime returned values in a volatile local variable before using
- * them in a function call.
- * 1995.04.11 MM Ensure that the Code Fragment is loaded into the System Heap.
- * 1995.04.29 MM Split into LogLibrary (PPC) and LogLibrary68 (68000). This
- * was done for the benefit of the MacsBug dcmd. This change
- * resulted in a significant simplification of the code as all
- * of the cross-architecture code was moved to LogLibrary68.c.
- * 1995.05.25 MM Some minor cleanups (parameters marked "const"). Removed all
- * dependencies on the Name Registry. This is not trivial, but
- * removed a lot of code (and simplified the library).
- * 1995.05.26 MM Folded the 68000 code back into the PowerPC code; this means
- * that 68000 modules can do everything except create a LogRecord.
- * Some of the ugliness is hidden in macros.
- */
-
- #include "LogLibrary.h"
- #define LOG (*logRecordPtr)
-
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
- #define EOS '\0'
-
- #if GENERATINGPOWERPC
- /*
- * This is the only global in the native LogLibrary. It must be exported "shared global."
- * If you change the name, be sure to change the argument to FindSymbol below.
- */
- LogRecordPtr _LogLibraryGlobal;
- #define GetFirstLogRecord() (_LogLibraryGlobal)
- static OSStatus AddNewLogRecord( /* SecondaryInterruptHandler2 */
- void *p1,
- void *p2
- );
- #else
- #include <GestaltEqu.h>
- /*
- * 68000 only.
- */
- unsigned short __DisableInterrupts(void) = {
- 0x40C0, /* move sr,d0 */
- 0x46FC, 0x2600 /* move #0x2600,sr */
- };
- void __EnableInterrupts(unsigned long saveSR) = {
- 0x46EF, 0x0002 /* move 2(sp),sr */
- };
- /*
- * When compiled for 68000's, the first call to GetLogRecordPtr initalizes this so
- * GetLogRecordPtr can access the LogRecord linked list.
- */
- static LogRecordPtr GetFirstLogRecord(void);
-
- #endif
-
- static Boolean32 EnableLogCapability(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 callerRequest, /* TRUE to enable something */
- UInt32 enableMaskBit /* Selector bitmask */
- );
- static Boolean StringEquals(
- const char *str1,
- const char *str2
- );
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * MakeLogRecord
- *
- * The first time this function is called after the system is started, it creates a
- * log record for this name. The log is initially enabled, and deletes overflow at the
- * start. It thus retains the *end* of the log -- this is useful for ongoing logging,
- * but may lose the start of a disaster sequence (as it records the flow of errors
- * through the system, rather than the intial cause.
- *
- * Returns the LogRecordPtr for this log, or NULL if unsuccessful.
- *
- * Only the "native" compilation can create LogRecords. When compiled for 68000's,
- * MakeLogRecord is identical to GetLogRecordPtr. This is needed to minimize
- * cross-language confusion.
- */
- pascal LogRecordPtr
- MakeLogRecord(
- const LogRecordNamePtr logRecordNamePtr, /* Log name (C-string) */
- UInt32 nEntries /* Number of Log entries */
- )
- {
- LogRecordPtr logRecordPtr; /* This log record */
- #if GENERATINGPOWERPC
- UInt32 logRecordSize;
- OSStatus osStatus;
- #endif
-
- logRecordPtr = GetLogRecordPtr(logRecordNamePtr);
- #if GENERATINGPOWERPC
- if (logRecordPtr == NULL) {
- /*
- * The log record is not in our linked list.
- *
- * Hand-compute the LogEntryRecord size to make sure that compiler quirks
- * don't mess us up. We check that kSizeofLogEntry equals sizeof
- * (LogEntryRecord). The ANSI C Standard does not permit "sizeof" in a
- * #define statement, so this check must be made at runtime.
- *
- * Note: do not replace the hard-coded numbers by sizeof statements:
- * this strange sequence ensures that the library can be complied
- * by several compilers.
- */
- #define kSizeofLogRecordEntry \
- ( 8 /* sizeof eventTime */ \
- + 4 /* sizeof sequence */ \
- + 4 /* sizeof idCode */ \
- + 4 /* sizeof format */ \
- + (4 * kLogEntryDataSize) /* sizeof data[] */ \
- )
- if (sizeof (LogEntryRecord) == kSizeofLogRecordEntry /* Size ok? */
- && nEntries > 0) { /* Has entries? */
- /*
- * We must create a new log record. The actual record has one extra
- * entry to prevent the "full vs. empty" bug.
- */
- logRecordSize = sizeof (LogRecord)
- + (nEntries * sizeof (LogEntryRecord));
- logRecordPtr = (LogRecordPtr)
- PoolAllocateResident(logRecordSize, TRUE);
- if (logRecordPtr != NULL) {
- /*
- * Initialize the LogRecord
- */
- LOG.entryMaxIndex = nEntries + 1;
- LOG.sequenceCounter = 1;
- CStrNCopy(
- LOG.logName,
- (char *) logRecordNamePtr,
- sizeof LOG.logName - 1
- );
- LOG.flags = ( (1 * kLogDataEnabledMask) /* Enabled */
- | (0 * kLogDataPreserveFirstMask) /* Save last */
- | (1 * kLogDataRecordUpTimeMask) /* Record UpTime */
- | (0 * kLogDataWrapAroundMask) /* Always zero */
- );
- osStatus = CallSecondaryInterruptHandler2(
- AddNewLogRecord,
- NULL,
- logRecordPtr,
- NULL
- );
- if (osStatus != noErr) {
- PoolDeallocate((LogicalAddress) logRecordPtr);
- /*
- * The only (expected) error indicates asynchronous creation.
- * We should be able to get the LogRecord now.
- */
- logRecordPtr = GetLogRecordPtr(logRecordNamePtr);
- }
- }
- }
- }
- #else /* 68000 only */
- do {
- nEntries = nEntries; /* Unused for 68000 */
- } while (0);
- #endif /* GENERATINGPOWERPC */
- return (logRecordPtr);
- }
-
- #if GENERATINGPOWERPC
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * AddNewLogRecord
- *
- * This is the only function to add a LogRecord. It is a Secondary Interrupt routine so
- * that only one caller can add a record.
- */
- static OSStatus
- AddNewLogRecord(
- void *p1,
- void *p2
- )
- {
- OSStatus osStatus;
- LogRecordPtr logRecordPtr;
- Boolean updated;
-
- (p2 = p2); /* Parameter p2 is unused */
- logRecordPtr = (LogRecordPtr) p1;
- /*
- * If several tasks try to add the same record, there is a tiny chance that
- * this function can be entered with the record already added, even though
- * MakeLogRecord checked for this. Thus, we check here (since Secondary
- * Interrupts are not re-entrant). If the record is now present, this function
- * returns an error status and MakeLogRecord disposes of the newly-created
- * (and now redundant) LogRecord and then re-calls GetLogRecordPtr to fetch
- * the correct LogRecordPtr.
- */
- if (GetLogRecordPtr(LOG.logName) != NULL)
- osStatus = fBsyErr;
- else {
- do {
- LOG.logRecordLink = _LogLibraryGlobal;
- updated = CompareAndSwap( /* Is CompareAndSwap needed? */
- (UInt32) LOG.logRecordLink,
- (UInt32) logRecordPtr,
- (UInt32 *) &_LogLibraryGlobal
- );
- } while (updated == FALSE);
- osStatus = noErr;
- }
- return (osStatus);
- }
- #endif /* GENERATINGPOWERPC */
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * GetLogRecordPtr
- *
- * Find the address of the LogRecord.
- */
- pascal LogRecordPtr
- GetLogRecordPtr(
- const LogRecordNamePtr logRecordNamePtr /* Log name (C-string) */
- )
- {
- LogRecordPtr logRecordPtr;
-
- logRecordPtr = GetFirstLogRecord();
- for (; logRecordPtr != NULL; logRecordPtr = LOG.logRecordLink) {
- if (StringEquals((const char *) logRecordNamePtr, LOG.logName))
- break;
- }
- return (logRecordPtr);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CopyLogRecordInfo
- *
- * This function copies the permanent part of the LogRecord (srcLogRecordPtr) to a
- * caller-designated area (dstLogRecordPtr). It is only for the benefit of the DCMD.
- * It returns noErr if successful, paramErr if either the source or destination parameters
- * are incorrect, or a Shared Library Manager error. This function ignores the interlock
- * semaphore. Thus, it may return inconstent data. It does not copy the first LogRecordEntry.
- *
- * Only the DCMD is permitted to call this function!
- */
- pascal OSErr
- CopyLogRecordInfo(
- const LogRecordPtr srcLogRecordPtr,
- LogRecordPtr dstLogRecordPtr
- )
- {
- OSErr status;
-
- if (srcLogRecordPtr == NULL || dstLogRecordPtr == NULL)
- status = paramErr;
- else {
- #if GENERATINGPOWERPC
- BlockCopy( /* Driver Suppor Library only */
- #else
- BlockMoveData( /* Macintosh Toolbox only */
- #endif
- srcLogRecordPtr,
- dstLogRecordPtr,
- sizeof (LogRecord) - sizeof (LogEntryRecord)
- );
- status = noErr;
- }
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * (LogString)
- *
- * This is a function version of the LogEntryString macro.
- */
- pascal OSErr
- (LogString)(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode, /* Entry identifier */
- ConstStr255Param string /* The datum */
- )
- {
- OSErr status;
-
- status = WriteLogEntry(logRecordPtr, idCode, LogStringFormat, string);
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * (LogStatusString)
- *
- * This is a function version of the LogDataStatusString macro.
- */
- pascal OSErr
- (LogStatusString)(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode, /* Entry identifier */
- OSErr callerStatus, /* Status error code */
- ConstStr255Param string /* The datum */
- )
- {
- OSErr status;
-
- status = WriteLogEntry(
- logRecordPtr,
- idCode,
- LogStatusFormat,
- (signed long) callerStatus,
- string
- );
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * WriteLogEntry
- *
- * This function logs data if logging is enabled.
- * idCode A user-controlled value, by convention an OSType (4-byte
- * character), that identifies this entry. The display program
- * prints it.
- * format The format of the remaining data: kLogFormatString if the
- * datum is a pascal string, otherwise, it is as created by the
- * LogFormat macro.
- * ... Additional data as needed. These values must be cast to
- * longwords to prevent ThinkC/MPW incompatibilities.
- * Note: The MixedMode Manager does not support variable-length argument lists.
- * Hence, this function is always in the "current" architecture.
- */
- OSErr
- WriteLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode,
- UInt32 format,
- ...
- )
- {
- va_list argPtr;
- register UInt32 *destPtr;
- LogEntryRecord theEntry;
- UInt16 maxString;
- register UInt16 stringLength;
- register UInt16 i;
- UInt16 thisFormat;
- StringPtr theString;
- OSErr status;
- #define ENTRY (theEntry)
-
- if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
- status = noErr;
- else {
- ENTRY.idCode = idCode;
- ENTRY.format = format;
- va_start(argPtr, format);
- destPtr = ENTRY.data;
- maxString = sizeof (ENTRY.data);
- while (maxString > 0) {
- thisFormat = format & kLogFormatMask;
- switch (thisFormat) {
- case kLogFormatEnd:
- goto exitLoop;
- case kLogFormatString:
- theString = va_arg(argPtr, StringPtr);
- if (theString == NULL)
- theString = "\p{null}";
- stringLength = theString[0];
- if (stringLength >= maxString)
- stringLength = maxString - 1;
- for (i = 1; i <= stringLength; i++)
- ((Ptr) destPtr)[i] = theString[i];
- ((Ptr) destPtr)[0] = stringLength;
- goto exitLoop;
- default: /* Signed or unsigned long value */
- *destPtr++ = va_arg(argPtr, unsigned long);
- format >>= kLogFormatShift;
- maxString -= sizeof (unsigned long);
- break;
- }
- }
- exitLoop: va_end(nextArg);
- status = StoreLogEntry(logRecordPtr, &theEntry);
- } /* If the LogData record exists */
- return (status);
- #undef ENTRY
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * StoreLogEntry
- *
- * Store a formatted LogEntryRecord in the log. This is the only routine that
- * writes the log entry. Normally, it is only called by WriteLogData.
- */
- pascal OSErr
- StoreLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- const LogEntryPtr logEntryPtr /* Gets this entry */
- )
- {
- OSErr status;
-
- UInt32 putIndex;
- UInt32 getIndex;
- #define ENTRY (*logEntryPtr)
-
- if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
- status = noErr;
- else {
- if ((LOG.flags & kLogDataRecordUpTimeMask) == 0)
- ENTRY.eventTime.hi = ENTRY.eventTime.lo = 0;
- else {
- ENTRY.eventTime = UpTime();
- }
- #if GENERATINGPOWERPC
- ENTRY.sequence = IncrementAtomic((SInt32 *) &LOG.sequenceCounter);
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Return "busy" */
- }
- else { /* Nope, we got it */
- #else
- {
- short oldSR = __DisableInterrupts();
-
- ENTRY.sequence = LOG.sequenceCounter++;
- #endif
- /*
- * The ring buffer is designed so that put == get implies empty
- * and pointers are always incremented before use.
- */
- putIndex = LOG.entryPutIndex + 1;
- if (putIndex >= LOG.entryMaxIndex) {
- putIndex = 0;
- LOG.flags |= kLogDataWrapAroundMask;
- }
- if (putIndex == LOG.entryGetIndex) { /* Did it fill? */
- if ((LOG.flags & kLogDataPreserveFirstMask) != 0)
- status = writErr; /* Keeping first */
- else {
- /*
- * We want to retain the latest entry. Do this by
- * advancing the "get" pointer as if the earliest entry
- * has been read. Then jump around the if bracket to store
- * this datum.
- */
- getIndex = LOG.entryGetIndex + 1;
- if (getIndex >= LOG.entryMaxIndex)
- getIndex = 0;
- LOG.entryGetIndex = getIndex;
- goto storeDatum;
- }
- }
- else {
- storeDatum: LOG.entries[putIndex] = ENTRY;
- LOG.entryPutIndex = putIndex;
- status = noErr; /* Data stored ok */
- }
- #if GENERATINGPOWERPC
- LOG.semaphore = 0; /* Free semaphore */
- #else
- __EnableInterrupts(oldSR);
- #endif
- }
- }
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * ReadLogEntry
- *
- * Read the next LogRecord entry. This returns a copy of the entry, if one is
- * available. The following status may be returned:
- * noErr Valid data was returned.
- * readErr No data is available.
- * fBsyErr The semaphore was locked by another function (presumable writing
- * into the log). Try again later.
- * other Code Fragment error.
- */
- pascal OSErr
- ReadLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- LogEntryPtr thisLogEntry /* Store entry here */
- )
- {
- OSErr status;
- UInt32 getIndex;
-
- status = readErr; /* Presume no data */
- if (logRecordPtr != NULL && thisLogEntry != NULL) {
- #if GENERATINGPOWERPC
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Inform caller */
- }
- else { /* Nope, we got it */
- #else
- {
- int oldSR = __DisableInterrupts();
- #endif
- getIndex = LOG.entryGetIndex;
- if (getIndex != LOG.entryPutIndex) { /* Not empty? */
- status = noErr;
- if (++getIndex >= LOG.entryMaxIndex)
- getIndex = 0;
- *thisLogEntry = LOG.entries[getIndex];
- LOG.entryGetIndex = getIndex;
- }
- #if GENERATINGPOWERPC
- LOG.semaphore = 0; /* Free semaphore */
- #else
- __EnableInterrupts(oldSR);
- #endif
- }
- }
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CopyLogEntry
- *
- * Copy the specified LogRecord entry. This returns a copy of the entry, return TRUE
- * if it was in range. This is only used by the DCMD to snapshot a LogRecord.
- */
- pascal OSErr
- CopyLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- UInt32 getIndex, /* This entry index */
- LogEntryPtr thisLogEntry /* Store entry here */
- )
- {
- OSErr status;
-
- status = readErr;
- if (logRecordPtr != NULL && getIndex < LOG.entryMaxIndex) {
- #if GENERATINGPOWERPC
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Inform caller */
- }
- else { /* Nope, we got it */
- #else
- {
- int oldSR = __DisableInterrupts();
- #endif
- status = noErr; /* Inform caller */
- *thisLogEntry = LOG.entries[getIndex]; /* Store result */
- #if GENERATINGPOWERPC
- LOG.semaphore = 0; /* Free semaphore */
- #else
- __EnableInterrupts(oldSR);
- #endif
- }
- }
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * EnableLogRecord
- *
- * Enable/disable logging. Returns the old logging state.
- */
- pascal Boolean32
- EnableLogRecord(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 enableLogging
- )
- {
- return (
- EnableLogCapability(logRecordPtr, enableLogging, kLogDataEnabledMask)
- );
- }
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * PreserveLogRecord
- *
- * Set the preserveFirst flag. Returns the old flag value.
- */
- pascal Boolean32
- PreserveLogRecord(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 preserveFirst
- )
- {
- return (
- EnableLogCapability(logRecordPtr, preserveFirst, kLogDataPreserveFirstMask)
- );
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * EnableLogUpTime
- *
- * Enable/disable recording of UpTime when WriteLogRecord. Returns the old state.
- * UpTime generally would be left in its original, enabled, state. The state may be
- * set FALSE to minimize the time needed to log data. If set FALSE, times will be
- * recorded as zero.
- */
- pascal Boolean32
- EnableLogUpTime(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 enableUpTime /* TRUE to enable UpTime */
- )
- {
- return (
- EnableLogCapability(logRecordPtr, enableUpTime, kLogDataRecordUpTimeMask)
- );
- }
-
- static Boolean32
- EnableLogCapability(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 callerRequest, /* TRUE to enable something */
- UInt32 enableMaskBit /* Selector bitmask */
- )
- {
- Boolean32 result;
- UInt32 oldFlag;
- UInt32 newFlag;
-
- if (logRecordPtr == NULL)
- oldFlag = 0;
- else {
- #if GENERATINGPOWERPC
- do {
- oldFlag = LOG.flags;
- if (callerRequest)
- newFlag = oldFlag | enableMaskBit;
- else {
- newFlag = oldFlag & ~enableMaskBit;
- }
- } while (CompareAndSwap(oldFlag, newFlag, &LOG.flags) == FALSE);
- #else
- int oldSR = __DisableInterrupts();
-
- oldFlag = LOG.flags;
- if (callerRequest)
- newFlag = oldFlag | enableMaskBit;
- else {
- newFlag = oldFlag & ~enableMaskBit;
- }
- __EnableInterrupts(oldSR);
- #endif
- }
- result = ((oldFlag & enableMaskBit) != 0);
- return (result);
- }
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * GetLogSemaphoreLostCounter
- *
- * Because the log library uses a "lossy" algorithm to maintain exclusive access to
- * the critical section, there is a very slight possibility that two processes will
- * try to access the log record at the same time. In this case, ReadLogEntry will
- * stall (loop) and eventually succeed, while WriteLogEntry will lose the datum, and
- * increment the logLostCounter.
- */
- pascal UInt32
- GetLogSemaphoreLostCounter(
- LogRecordPtr logRecordPtr /* This log record */
- )
- {
- UInt32 result;
-
- result = ((logRecordPtr == NULL) ? 0 : LOG.lostLockCounter);
- return (result);
- }
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogRecord utilities.
- *
- * These three functions are used to locate all registered log records. They may be
- * used for a display utility or MacsBug dcmd. Applications call them as follows:
- *
- * LogRecordIter cookie;
- *
- * if (LogRecordIterateCreate(&cookie) == noErr) {
- * while ((logRecordPtr = LogRecordIterate(&cookie)) != NULL) {
- * ... Process this LogRecord, the name may be extracted from the record ...
- * }
- * LogRecordIterateDispose(&cookie);
- * }
- */
- pascal OSErr
- LogRecordIterateCreate(
- LogRecordIterPtr cookie
- )
- {
- OSErr status;
-
- cookie->logRecordPtr = GetFirstLogRecord();
- status = noErr;
- return (status);
- }
-
- pascal void
- LogRecordIterateDispose(
- LogRecordIterPtr cookie
- )
- {
- cookie->logRecordPtr = NULL;
- /* Nothing to dispose */;
- }
-
- pascal LogRecordPtr
- LogRecordIterate(
- LogRecordIterPtr cookie
- )
- {
- LogRecordPtr logRecordPtr;
-
- logRecordPtr = cookie->logRecordPtr;
- if (logRecordPtr != NULL)
- cookie->logRecordPtr = LOG.logRecordLink;
- return (logRecordPtr);
- }
-
- #if GENERATINGPOWERPC
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogUpTime
- *
- * This is the DriverServicesLibrary UpTime function, callable from 68000. It is
- * called, once, by LogConvertTimestamp.
- *
- * Return values
- * resultPtr AbsoluteTime
- */
- pascal void
- LogUpTime(
- AbsoluteTime *resultPtr
- )
- {
- *resultPtr = UpTime();
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogGetTimeBaseInfo
- *
- * This is the DriverServicesLibrary UpTime function, callable from 68000. It returns
- * only those values that LogConvertTimestamp needs.
- *
- * Return values
- * upTimeNumerator Needed for our AbsoluteToNanoseconds
- * upTimeDenominator Needed for our AbsoluteToNanoseconds
- */
- pascal void
- LogGetTimeBaseInfo(
- UInt32 *upTimeNumerator,
- UInt32 *upTimeDenominator
- )
- {
- UInt32 unused;
-
- GetTimeBaseInfo(
- &unused, /* minAbsoluteTimeDelta - unused */
- upTimeNumerator, /* For AbsoluteTimeToNanoseconds */
- upTimeDenominator, /* For AbsoluteTimeToNanoseconds */
- &unused, /* Unused */
- &unused /* Unused */
- );
- }
- #else
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogUpTime
- *
- * This is the DriverServicesLibrary UpTime function, callable from 68000. It is
- * called, once, by LogConvertTimestamp. Note: PowerPCClock trashes A3. The inline
- * assembly is rather inefficient; but, of course, it is only called once.
- *
- * Return values
- * resultPtr AbsoluteTime
- */
- void PowerPCClock(
- AbsoluteTime *result
- ) = {
- 0x205F, /* movea.l (sp)+,a0 ; Fetch result address */
- 0x48E7, 0x7F7E, /* movem.l d1-d7/a1-a6,-(sp) ; Save all registers */
- 0x2F08, /* move.l a0,-(sp) ; Save result address */
- 0xFE09, /* dc.w 0xFE09 ; Get UpTime from emulator */
- 0x225F, /* movea.l (sp)+,a1 ; Retrieve result address */
- 0x2288, /* move.l a0,(a1) ; Store result low word */
- 0x2340, 0x0004, /* move.l d0,4(a1) ; Store result high word */
- 0x4CDF, 0x7EFE /* movem.l (sp)+,d1-d7/a1-a6 ; Restore all registers */
- };
-
- pascal void
- LogUpTime(
- AbsoluteTime *resultPtr
- )
- {
- PowerPCClock(resultPtr);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogGetTimeBaseInfo
- *
- * This is the DriverServicesLibrary UpTime function, callable from 68000. It returns
- * only those values that LogConvertTimestamp needs.
- *
- * Return values
- * upTimeNumerator Needed for our AbsoluteToNanoseconds
- * upTimeDenominator Needed for our AbsoluteToNanoseconds
- */
- pascal void
- LogGetTimeBaseInfo(
- UInt32 *upTimeNumerator,
- UInt32 *upTimeDenominator
- )
- {
- *upTimeNumerator = 4085; /* These hard-wired values are only valid */
- *upTimeDenominator = 4096; /* For the current "PowerSurge" machines */
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * GetFirstLogRecord
- *
- * The first time GetLogLibaryGlobal is called, it uses the Code Fragment Manager to
- * locate _LogLibaryGlobal. If successful, it returns the contents of _LogLibraryGlobal.
- * If it fails, it returns NULL.
- */
- static LogRecordPtr
- GetFirstLogRecord(void)
- {
- OSErr status;
- LogRecordPtr logRecordPtr;
- THz currentHeap;
- long gestaltResponse;
- CFragConnectionID connectionID;
- CFragSymbolClass symbolClass;
- Ptr mainEntryAddr;
- Str255 errorName;
- static LogRecordPtr *gLogLibraryGlobalPtr;
-
- if (gLogLibraryGlobalPtr == NULL) {
- status = Gestalt(gestaltCFMAttr, &gestaltResponse);
- if (status == noErr
- && (gestaltResponse & (1 << gestaltCFMPresent)) == 0)
- status = gestaltUndefSelectorErr;
- if (status == noErr) {
- currentHeap = GetZone();
- SetZone(SystemZone());
- status = GetSharedLibrary(
- "\pLogLibrary",
- kPowerPCCFragArch,
- kLoadCFrag,
- &connectionID,
- &mainEntryAddr,
- errorName
- );
- SetZone(currentHeap);
- }
- if (status == noErr) {
- status = FindSymbol(
- connectionID,
- "\p_LogLibraryGlobal",
- (Ptr *) &gLogLibraryGlobalPtr,
- &symbolClass
- );
- }
- if (status != noErr)
- gLogLibraryGlobalPtr = (LogRecordPtr *) -1L; /* failure */
- }
- logRecordPtr = (gLogLibraryGlobalPtr != (LogRecordPtr *) -1L)
- ? *gLogLibraryGlobalPtr : NULL;
- return (logRecordPtr);
- }
- #endif /* GENERATINGPOWERPC */
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * StringEquals
- *
- * Compare two strings, returning TRUE if equal. This eliminates dependency on
- * the DriverServices Library.
- */
- static Boolean
- StringEquals(
- const char *str1,
- const char *str2
- )
- {
- while (*str1 == *str2) {
- if (*str1++ == 0)
- return (TRUE);
- ++str2;
- }
- return (FALSE);
- }
-